<?php
// 应用公共文件

use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use AlibabaCloud\SDK\Dysmsapi\V20170525\Models\SendSmsRequest;

use AlibabaCloud\SDK\Dysmsapi\V20170525\Dysmsapi;
use AlibabaCloud\Credentials\Credential;
use AlibabaCloud\Dara\Models\RuntimeOptions;
use AlibabaCloud\Tea\Exception\TeaError;

use AlibabaCloud\Oss\V2 as Oss;

use Darabonba\OpenApi\Models\Config;
use app\ConstVar;
use app\model\SmsCodeModel;
use think\Exception;

/**
 * 统一接口返回格式
 * @param array $data 返回数据
 * @param string $message 提示信息
 * @param int $code 状态码：1成功，0失败
 * @return \think\response\Json JSON格式的响应
 */
function api_response(array $data = [], string $message = 'success', int $code = 1)
{
    return json([
        'code' => $code,
        'message' => $message,
        'data' => $data
    ]);
}

/**
 * 参数转义处理
 * @param mixed $param 需要处理的参数
 * @param string $type 参数类型：int整型，float浮点型，string字符串，array数组，bool布尔值
 * @param mixed $default 默认值
 * @return mixed 处理后的参数
 */
function param_filter($param, string $type = 'string', $default = '')
{
    // 如果参数为null或空字符串，则返回默认值
    if ($param === null || $param === '') {
        return $default;
    }

    switch ($type) {
        case 'int':
            // 整型转换
            return intval($param);
        case 'float':
            // 浮点型转换
            return floatval($param);
        case 'string':
            // 字符串转义，防止XSS攻击和SQL注入
            return htmlspecialchars(trim(strval($param)), ENT_QUOTES);
        case 'array':
            // 数组处理
            return is_array($param) ? $param : [$param];
        case 'bool':
            // 布尔值转换
            return boolval($param);
        default:
            // 默认按字符串处理
            return htmlspecialchars(trim(strval($param)), ENT_QUOTES);
    }
}

/**
 * 随机生成验证码
 *
 * @param integer $length
 * @return string
 */
function generateRandomVerifyCode($length = 6): string
{
    $chars = '0123456789';
    $charsLength = strlen($chars) - 1;
    $randomCode = '';
    for ($i = 0; $i < $length; $i++) {
        $randomCode .= $chars[rand(0, $charsLength)];
    }
    return $randomCode;
}

/**
 * 随机生成16位的盐
 *
 * @param integer $length
 * @return void
 */
function generateRandomSalt($length = 16)
{
    $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    $randString = '';
    for ($i = 0; $i < $length; $i++) {
        $randString .= $chars[rand(0, strlen($chars) - 1)];
    }
    return $randString;
}


/**
 * 随机生成密码（明文）
 *
 * @param integer $length
 * @return void
 */
function generateRandomPassword($length = 8)
{
    // 定义字符集
    $digits = '0123456789';
    $letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $allChars = $digits . $letters;

    // 确保密码长度至少为2
    $length = max($length, 2);

    $password = '';
    // 首先生成一个随机数字
    $password .= $digits[random_int(0, strlen($digits) - 1)];
    // 再生成一个随机字母
    $password .= $letters[random_int(0, strlen($letters) - 1)];

    // 生成剩余字符
    for ($i = 2; $i < $length; $i++) {
        $password .= $allChars[random_int(0, strlen($allChars) - 1)];
    }

    // 打乱字符串以增加随机性
    return str_shuffle($password);
}

/**
 * 创建访问令牌
 *
 * @param array $arrData
 * @return string
 */
function createAccessToken(array $arrData): string
{
    if (empty($arrData)) {
        return '';
    }
    $arrData['iat'] = time(); //签发时间
    $arrData['exp'] = time() + env('JWT_EXPIRES_TIME'); //过期时间
    return  JWT::encode(
        $arrData,
        env('JWT_SECRET_KEY'),
        env('JWT_ALGORITHM')
    );
}


/**
 * 解析访问令牌
 *
 * @param string $token
 * @return array
 */
function parseAccessToken(string $strAccessToken): array
{
    if (empty($strAccessToken)) {
        return [];
    }
    $arrDecoded = JWT::decode($strAccessToken, new Key(env('JWT_SECRET_KEY'), env('JWT_ALGORITHM')));
    return (array)$arrDecoded;
}

/**
 * 发送验证码
 *
 * @param string $strPhone
 * @param string $strCode
 * @return boolean
 */
function sendVerifyCode(string $strPhone, string $strCode): bool
{
    try {
        if (empty($strPhone) || empty($strCode)) {
            return false;
        }

        $config = new Config([
            "accessKeyId" => env("ALIYUN_SMS_ACCESS_KEY_ID"),
            "accessKeySecret" => env("ALIYUN_SMS_ACCESS_KEY_SECRET"),
            "credential" => new Credential()
        ]);
        $config->endpoint = "dysmsapi.aliyuncs.com";
        $client = new Dysmsapi($config);

        $sendSmsRequest = new SendSmsRequest([
            "phoneNumbers" => $strPhone,
            "signName" => ConstVar::SMS_SIGN_NAME_REGIST,
            "templateCode" => ConstVar::SMS_TEMPLATE_CODE_REGIST,
            "templateParam" => json_encode(["code" => $strCode])
        ]);
        $runtime = new RuntimeOptions([]);

        // 复制代码运行请自行打印 API 的返回值
        $objResp = $client->sendSmsWithOptions($sendSmsRequest, $runtime);
        if ($objResp->body->code != "OK") {
            return false;
        }
        return true;
    } catch (Exception $error) {
        if (!($error instanceof TeaError)) {
            $error = new TeaError([], $error->getMessage(), $error->getCode(), $error);
        }
        throw $error;
    }
}

/**
 * 校验验证码是否正确
 *
 * @param string $strPhone
 * @param string $strVerifyCode
 * @return boolean
 */
function checkVerifyCodeIsOk(string $strPhone, string $strVerifyCode): bool
{
    if (empty($strPhone) || empty($strVerifyCode)) {
        return false;
    }
    $strInfo = SmsCodeModel::getOneByWhere([['phone', '=', $strPhone]]);
    if (empty($strInfo)) {
        return false;
    }
    if ($strInfo['expire_time'] < time()) {
        throw new Exception('验证码已过期，请重新获取');
    }
    if ($strInfo['code'] != $strVerifyCode) {
        return false;
    }
    return true;
}

/**
 * 上传文件到oss
 *
 * @param string $objFile 文件对象
 * @param string $strNewFilePath    新文件路径
 * @return void
 */
function uploadToOss(string $objFile, string $strNewFilePath)
{
    // 从解析的参数中提取值
    $strRegion = ConstVar::OSS_REGION; // Bucket所在的地域
    $strBucket = ConstVar::OSS_BUCKET; // Bucket名称
    $strKey = $strNewFilePath;       // 对象名称

    $strEndPoint = ConstVar::OSS_ENDPOINT;

    // 加载配置信息
    $credentialsProvider = new Oss\Credentials\StaticCredentialsProvider(
        env('ALIYUN_SMS_ACCESS_KEY_ID'),
        env('ALIYUN_SMS_ACCESS_KEY_SECRET'),
        // $strStsToken = '' // 可选，STS令牌，用于临时访问凭证
    );
    $credentialsProvider->getCredentials();

    // 使用SDK的默认配置
    $cfg = Oss\Config::loadDefault();
    $cfg->setCredentialsProvider($credentialsProvider); // 设置凭证提供者
    $cfg->setRegion($strRegion); // 设置Bucket所在的地域
    $cfg->setEndpoint($strEndPoint); // 如果提供了访问域名，则设置endpoint


    // 创建OSS客户端实例
    $client = new Oss\Client($cfg);

    // 检查文件是否存在
    if (!file_exists($objFile)) {
        throw new Exception('文件不存在');
    }

    // 打开文件并准备上传
    // 使用fopen以只读模式打开文件，并通过Utils::streamFor将文件内容转换为流
    $body = Oss\Utils::streamFor(fopen($objFile, 'r'));

    // 创建PutObjectRequest对象，用于上传文件
    $request = new Oss\Models\PutObjectRequest(bucket: $strBucket, key: $strKey);
    $request->body = $body; // 设置请求体为文件流

    // 执行上传操作
    $result = $client->putObject($request);
    if ($result->status != 'OK') {
        return false;
    }
    return true;
}
